#ifndef A8_STRINGLIST_H
#define A8_STRINGLIST_H

#include <stdio.h>
#include <string>
#include <string.h>
#include <vector>

namespace a8
{
    class StringList
    {
    private:

        class StringItem
        {
        public:
            std::string mString;
            void* mObject;

            StringItem(const char* str, void* obj = NULL):mString(str), mObject(obj) {}
        };

    public:

        StringList():mSorted(false), mCaseSensitive(false)
        {
        }

        ~StringList()
        {
            mStringItemList.clear();
        }

        bool LoadFromFile(const char* szFile)
        {
            mStringItemList.clear();
            FILE *fp = fopen(szFile, "rb");
            if(fp){
                fseek(fp, 0, SEEK_END);
                int fileSize = ftell(fp);
                if(fileSize){
                    char *p = (char*)malloc(fileSize + 1);
                    if(p){
                        *(p + fileSize) = '\0';
                        fseek(fp, 0, SEEK_SET);
                        fread(p, 1, fileSize, fp);
                        setText(p);
                        free(p);
                    }
                }
                fclose(fp);
                return true;
			}else{
                return false;
			}
        }

        int SaveToFile(const char* szFile)
        {
            FILE *fp = fopen(szFile, "w");
            if(fp){
                for(std::vector<StringItem>::const_iterator itr = mStringItemList.begin(); itr != mStringItemList.end(); itr++){
                    fwrite(itr->mString.c_str(), itr->mString.length(), itr->mString.length(), fp);
                    fprintf(fp, "\r\n");
                }
                fclose(fp);
                return 1;
            }else
                return 0;
        }

        std::string operator[](int idx)
        {
            return String(idx);
        }

        void Add(const char* szStr)
        {
            AddObject(szStr, NULL);
        }

        void Add(const char* szStr1, const char* szStr2)
        {
            if(szStr2 - szStr1 > 0){
                std::string str(szStr1, szStr2 - szStr1);
                Add(str.c_str());
            }else
                Add("\r\n");
        }

        void AddObject(const char* szStr, void* obj)
        {
            StringItem newItem(szStr, obj);
            mStringItemList.push_back(newItem);      
        }

        int Count()
        {
            return mStringItemList.size();
        }

        void Delete(unsigned int idx)
        {
            if(idx > 0 && idx < mStringItemList.size()){
                mStringItemList.erase(mStringItemList.begin() + idx);
            }
        }

        std::string Text() const 
        {
            std::string result;
            for(std::vector<StringItem>::const_iterator itr = mStringItemList.begin(); itr != mStringItemList.end(); itr++){
                result.append(itr->mString.c_str());
                result.append("\r\n");
            }
            return result;
        }

        int IndexOf(const char* szStr)
        {
            for(std::vector<StringItem>::const_iterator itr = mStringItemList.begin(); itr != mStringItemList.end(); itr++){		
#ifdef _MSC_VER
	      if((mCaseSensitive && _stricmp(itr->mString.c_str(), szStr)==0) ||
#else
	      if((mCaseSensitive && strcasecmp(itr->mString.c_str(), szStr)==0) ||
#endif		 
                   (!mCaseSensitive &&  strcmp(itr->mString.c_str(), szStr)==0))
                    return itr - mStringItemList.begin();
            }
            return -1;
        }

        void Insert(unsigned int idx, const char* szStr)
        {
            StringItem newItem(szStr);
            if(idx < mStringItemList.size())
                mStringItemList.insert(mStringItemList.begin() + idx, newItem);
            else
                Add(szStr);
        }

        void Exchange(unsigned int idxA, unsigned int idxB)
        {
            if(idxA >=0 && idxA < mStringItemList.size() && 
               idxB >=0 && idxB < mStringItemList.size() && idxA != idxB){
                StringItem tmp = mStringItemList[idxA];
                mStringItemList[idxA] = mStringItemList[idxB];
                mStringItemList[idxB] = tmp;
            }
        }

        std::string String(unsigned int idx) 
        {
            if(idx >=0 && idx < mStringItemList.size())
                return mStringItemList[idx].mString;
            return "";
        }

        void* Object(unsigned int idx)
        {
            if(idx >= 0 && idx < mStringItemList.size())
                return mStringItemList[idx].mObject;
            return NULL;
        }

        std::string Names(int idx)
        {
            std::string str = String(idx);
            std::size_t iPos = str.find('=');
            if(iPos != std::string::npos)
                return str.substr(0, iPos - 1);
            else
                return "";
        }

        std::string ValueFromIndex(int idx) 
        {
            std::string str = String(idx);
            std::size_t iPos = str.find('=');
            if(iPos != std::string::npos)
                return str.substr(iPos + 1, str.length() - iPos);
            else
                return "";
        }

        std::string Values(const char* szName)
        {
            for(unsigned int i = 0; i < mStringItemList.size(); i++){
#ifdef _MSC_VER
                if((mCaseSensitive && _stricmp(mStringItemList[i].mString.c_str(), szName)==0) ||
#else
                if((mCaseSensitive && strcasecmp(mStringItemList[i].mString.c_str(), szName)==0) ||
#endif
                   (!mCaseSensitive && strcmp(mStringItemList[i].mString.c_str(), szName)==0)){
                    return ValueFromIndex(i);
                }
            }
            return "";
        }

        int CaseSensitive()
        {
            return mCaseSensitive;
        }

        void Sort()
        {

        }

        void setString(unsigned int idx, const char* szStr)
        {
            if(idx>=0 && idx<mStringItemList.size())
                mStringItemList[idx].mString.assign(szStr);
        }

        void setObject(unsigned int idx, void* pObj)
        {
            if(idx>=0 && idx<mStringItemList.size())
                mStringItemList[idx].mObject = pObj;
        }
    
        void setDelimitedText(const char* szText, char delimiter=',')
        {
            mStringItemList.clear();
            const char *p1 = szText;
            const char *p2 = szText;
            while(p2){
                if(*p2 == delimiter){
                    Add(p1, p2 - 1);
                    p1 = p2 + 1;
                }
                p2++;
            }
            if(p2 > p1)
                Add(p1, p2);
        }

        void setText(const char* szText)
        {
            mStringItemList.clear();
            const char *p1 = szText;
            const char *p2 = szText;
            while(*p2){
                if(*p2 == '\r' || *p2 == '\n'){
                    Add(p1, p2);
                    if(*p2 == '\r' && *(p2 + 1) == '\n')
                        p2++;
                    p1 = p2 + 1;
                }
                p2++;
            }
        }

        void setCaseSensitive(bool caseSensitive)
        {
            mCaseSensitive = caseSensitive;
        }

    private:
        std::vector<StringItem> mStringItemList;
        bool mSorted;
        bool mCaseSensitive;
    };
}

#endif
